package com.usian.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.usian.mapper.*;
import com.usian.pojo.*;
import com.usian.redis.RedisClient;
import com.usian.service.TbItemService;
import com.usian.utils.IDUtils;
import com.usian.utils.PageResult;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author chen
 * @date 2021/1/9 - 11:35 - 星期六
 * @project usian_parent
 * @package com.usian.service.impl
 * @by GGbomd猪猪侠
 */
@Service
@Transactional
public class TbItemServiceImpl implements TbItemService {

    @Autowired
    private TbItemMapper tbItemMapper;

    @Autowired
    private TbItemDescMapper tbItemDescMapper;

    @Autowired
    private TbItemParamItemMapper tbItemParamItemMapper;

    @Autowired
    private TbItemCatMapper tbItemCatMapper;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private RedisClient redisClient;

    @Value("${ITEM_INFO}")
    private String ITEM_INFO;

    @Value("${BASE}")
    private String BASE;

    @Value("${DESC}")
    private String DESC;

    @Value("${PARAM}")
    private String PARAM;

    //设置key存活的时间
    @Value("${ITEM_INFO_EXPIRE}")
    private long ITEM_INFO_EXPIRE;

    @Value("${SETNX_BASC_LOCK_KEY}")
    private String SETNX_BASC_LOCK_KEY;

    @Value("${SETNX_DESC_LOCK_KEY}")
    private String SETNX_DESC_LOCK_KEY;

    @Autowired
    private TbOrderItemMapper tbOrderItemMapper;

    @Override
    /**
     * 商品列表查询
     * @param page  页码
     * @param rows  每页显示的条数
     * @return
     */
    @RequestMapping("/selectTbItemAllByPage")
    public PageResult selectTbItemAllByPage(Integer page, Integer rows){
        //使用分页插件 传入页码和每页显示个数
        PageHelper.startPage(page,rows);
        //Helper 分页工具
        QueryWrapper<TbItem> tbItemQueryWrapper = new QueryWrapper<TbItem>();
        // eq比较
        tbItemQueryWrapper.eq("status",1);
        tbItemQueryWrapper.orderByDesc("updated");

        //mybait 自带的分页查询
        /*Page<TbItem> tbItemPage = new Page<>(page,rows);
        tbItemMapper.selectPage(tbItemPage,tbItemQueryWrapper);*/

        //查询数据返回一个集合
        List<TbItem> tbItemList = tbItemMapper.selectList(tbItemQueryWrapper);
        PageInfo<TbItem> pageInfo = new PageInfo<>(tbItemList);
        //返回以一个PageResult  需要把当前页，页码，总页数返回
        PageResult pageResult = new PageResult();
        pageResult.setPageIndex(pageInfo.getPageNum());//当前页
        pageResult.setTotalPage(pageInfo.getPages());//总页数
        pageResult.setResult(pageInfo.getList());//返回一个结果集
        return pageResult;
    }

    /**
     * 商品的添加  同时添加tb_item ，tb_item_desc ，tb_item_param_item
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Integer insertTbItem(TbItem tbItem, String desc, String itemParams) {
        //同时操添加3个表 先添加tb_item 不起前台没有传来的数据
        //获取到主键id
        long id = IDUtils.genItemId();
        Date date = new Date();
        tbItem.setId(id);
        tbItem.setStatus((byte)1);
        tbItem.setUpdated(date);
        tbItem.setCreated(date);
        tbItem.setPrice(tbItem.getPrice()*100);
        Integer tbItemNum = tbItemMapper.insert(tbItem);

        //补齐商品描述对象
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setItemId(id);
        tbItemDesc.setItemDesc(desc);
        tbItemDesc.setCreated(date);
        tbItemDesc.setUpdated(date);
        Integer tbitemDescNum = tbItemDescMapper.insert(tbItemDesc);

        //补齐商品规格参数
        TbItemParamItem tbItemParamItem = new TbItemParamItem();
        tbItemParamItem.setItemId(id);
        tbItemParamItem.setParamData(itemParams);
        tbItemParamItem.setUpdated(date);
        tbItemParamItem.setCreated(date);
        Integer itemParamItmeNum = tbItemParamItemMapper.insert(tbItemParamItem);

        //添加商品发布消息到mq  item_exchage声明一个交换机名字 item.add和教皇及绑定的
        // 需要用到mq来当消息中间在放到es里
        amqpTemplate.convertAndSend("item_exchage","item.add", id);
        return tbItemNum + tbitemDescNum + itemParamItmeNum;
    }

    /**
     * 商品的删除  同时删除tb_item 这个表状态改成status 3 删除 ，tb_item_desc删除 ，tb_item_param_item删除
     * @param itemId
     * @return
     */
    @Override
    public Integer deleteItemById(Long itemId) {
        // 删除 tb_item_param_item
        TbItemParamItem tbItemParamItem = tbItemParamItemMapper.findOne(itemId);
        Long id = tbItemParamItem.getId();
        int a = tbItemParamItemMapper.deleteByPrimaryKey(id);

        // 删除 tb_item_desc
        int b = tbItemDescMapper.deleteByPrimaryKey(itemId);

        // 修改tb_item表的状态 status 3 是删除
        TbItem tbItem = tbItemMapper.selectByPrimaryKey(itemId);
        tbItem.setStatus((byte)3);
        int c = tbItemMapper.updateByPrimaryKey(tbItem);

        //删除商品表里redis里的缓存
        String item = ITEM_INFO+":"+itemId+":"+BASE;
        String desc = ITEM_INFO+":"+itemId+":"+DESC;
        String paramItem = ITEM_INFO + ":" + id + ":"+ PARAM;
        redisClient.del(item);
        redisClient.del(desc);
        redisClient.del(paramItem);
        return a+b+c;
    }

    /**
     * 修改的回显
     * 根据商品 ID 查询商品，商品分类，商品描述，商品规格参数
     * @param itemId
     * @return
     */
    @Override
    public Map<String, Object> preUpdateItem(Long itemId) {
        Map<String, Object> map = new HashMap<>();
        //根据商品 ID 查询商品
        TbItem item = tbItemMapper.selectByPrimaryKey(itemId);
        map.put("item", item);
        //根据商品 ID 查询商品描述
        TbItemDesc itemDesc = tbItemDescMapper.selectByPrimaryKey(itemId);
        map.put("itemDesc", itemDesc.getItemDesc());
        //根据商品 ID 查询商品类目
        TbItemCat itemCat = tbItemCatMapper.selectByPrimaryKey(item.getCid());
        map.put("itemCat", itemCat.getName());
        //根据商品 ID 查询商品规格信息
        QueryWrapper<TbItemParamItem> tbItemParamItemQueryWrapper = new QueryWrapper<>();
        tbItemParamItemQueryWrapper.eq("item_id",itemId);
        List<TbItemParamItem> tbItemParamItems = tbItemParamItemMapper.selectList(tbItemParamItemQueryWrapper);
        if (tbItemParamItems != null && tbItemParamItems.size() > 0){
            map.put("itemParamItem", tbItemParamItems.get(0).getParamData());
        }
        return map;
    }

    /**
     * 根据商品id去修改   同时修改tb_item ，tb_item_desc ，tb_item_param_item
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Integer updateTbItem(TbItem tbItem, String desc, String itemParams) {
        //获取到回显数据的id
        Long id = tbItem.getId();
        Date date = new Date();
        tbItem.setStatus((byte)1);
        tbItem.setUpdated(date);
        tbItem.setPrice(tbItem.getPrice()*100);
        Integer tbItemNum = tbItemMapper.updateByPrimaryKeySelective(tbItem);

        //补齐商品描述对象
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setItemId(id);
        tbItemDesc.setItemDesc(desc);
        tbItemDesc.setUpdated(date);
        Integer tbitemDescNum = tbItemDescMapper.updateByPrimaryKeySelective(tbItemDesc);

        //补齐商品规格参数
        QueryWrapper<TbItemParamItem> tbItemParamItemQueryWrapper = new QueryWrapper<>();
        tbItemParamItemQueryWrapper.eq("item_id",id);
        // 根据id查询在根据tb_item_param_item主键id修改
        TbItemParamItem tbItemParamItem = tbItemParamItemMapper.selectOne(tbItemParamItemQueryWrapper);
        tbItemParamItem.setItemId(id);
        tbItemParamItem.setParamData(itemParams);
        tbItemParamItem.setUpdated(date);
        Integer itemParamItmeNum = tbItemParamItemMapper.updateByPrimaryKeySelective(tbItemParamItem);

        //删除商品表里redis里的缓存
        String item1 = ITEM_INFO+":"+id+":"+BASE;
        String desc1 = ITEM_INFO+":"+id+":"+DESC;
        String paramItem1 = ITEM_INFO + ":" + id + ":"+ PARAM;
        redisClient.del(item1);
        redisClient.del(desc1);
        redisClient.del(paramItem1);
        return tbItemNum+tbitemDescNum+itemParamItmeNum;
    }

    /**
     * 查询商品基本详细信息
     * @param itemId
     * @return
     */
    @Override
    public TbItem selectItemInfo(Long itemId) {
        //查询缓存
        String key = ITEM_INFO+":"+itemId+":"+BASE;
        TbItem tbItem = (TbItem) redisClient.get(key);
        if (tbItem!=null && tbItem.equals(redisClient.get(key))){
            return tbItem;
        }
        /*****************解决缓存击穿***************/
        // 设置30秒
        if (redisClient.setnx(SETNX_BASC_LOCK_KEY+":"+itemId,itemId,30L)){
            //2、再查询mysql,并把查询结果缓存到redis,并设置失效时间
            tbItem = tbItemMapper.selectByPrimaryKey(itemId);
            /********************解决缓存穿透************************/
            if (tbItem==null){
                redisClient.set(key,"不存在这条数据");
                redisClient.expire(key,30);
                return null;
            }
            //把数据保存到缓存
            redisClient.set(key,tbItem);
            //设置缓存的有效期
            redisClient.expire(key,ITEM_INFO_EXPIRE);
            return null;
        }else{
            try {
                Thread.sleep(1000);//睡眠一秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return selectItemInfo(itemId); //一秒之后再去调用这个方法
        }
    }

    /**
     * 根据商品 ID 查询商品描述
     * @param itemId
     * @return
     */
    @Override
    public TbItemDesc selectItemDescByItemId(Long itemId) {
        //查询缓存
        //1、先查询redis,如果有直接返回
        String key = ITEM_INFO+":"+itemId+":"+DESC;
        TbItemDesc tbItemDesc = (TbItemDesc) redisClient.get(key);
        if (tbItemDesc != null && tbItemDesc.equals(redisClient.get(key))){
            return tbItemDesc;
        }
        /*****************解决缓存击穿***************/
        // 设置30秒
        if (redisClient.setnx(SETNX_DESC_LOCK_KEY+":"+itemId,itemId,30L)){
            //2、再查询mysql,并把查询结果缓存到redis,并设置失效时间
            tbItemDesc = tbItemDescMapper.selectByPrimaryKey(itemId);
            /********************解决缓存穿透************************/
            if (tbItemDesc==null){
                redisClient.set(key,"不存在这条数据");
                redisClient.expire(key,30);
                return null;
            }
            //把数据保存到缓存
            redisClient.set(key,tbItemDesc);
            //设置缓存的有效期
            redisClient.expire(key,ITEM_INFO_EXPIRE);
            return tbItemDesc;
        }else {
            try {
                Thread.sleep(1000); //睡眠一秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return selectItemDescByItemId(itemId); //一秒之后再去调用这个方法
        }
    }

    /**
     * 修改商品库存数量
     * @param orderId
     * @return
     */
    public Integer updateTbItemByOrderId(String orderId){
        QueryWrapper<TbOrderItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",orderId);
        List<TbOrderItem> tbOrders = tbOrderItemMapper.selectList(queryWrapper);
        int result = 0;
        for (int i = 0; i < tbOrders.size(); i++) {
            // 通过Order_id 查询tb_item 修改库存数量
            TbOrderItem tbOrderItem =  tbOrders.get(i);
            TbItem tbItem = tbItemMapper.selectByPrimaryKey(Long.valueOf(tbOrderItem.getItemId()));
            tbItem.setNum(tbItem.getNum()-tbOrderItem.getNum());
            result += tbItemMapper.updateByPrimaryKeySelective(tbItem);
        }
        return result;
    }
}
